/***********************************************************************
 * BinTrotter : BitTorrent library/client for the Android operating system.
 *  
 * Copyright (C) 2009, Christopher David Stones (chris.stones@gmail.com)
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 ***********************************************************************/

package org.bintrotter.bdecode;

import java.io.FileInputStream;
import java.io.InputStream;
//import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Arrays;

public class InfoHash {

	public String SHA1String;
	public byte[] SHA1Bytes;
	
	public InfoHash(String fileName) throws Throwable {
		
		FileInputStream fis = new FileInputStream(fileName);
		
		try {
			run(fis);
		} finally {
			fis.close();
		}
	}
	
	public InfoHash(InputStream is) throws Throwable {
		
		run(is);
	}
	
	private void run(InputStream is) throws Throwable {
		
		SHA1String = null;
		SHA1Bytes = null;
		
		int b;
		
		StringBuilder sb;
		int length;
		byte[] stringData;
		int depth = 0;
		boolean inHash = false;
	
				
		MessageDigest md = MessageDigest.getInstance("SHA-1");

		while ( (b = is.read()) != -1) {
			
			switch(b) {
			case 'd':
				++depth;
			
				if(inHash) {
					md.update((byte)b);
				}
				
				break;
			case 'l':
				++depth;

				
				if(inHash) {
					md.update((byte)b);
				}
				
				break;
			case 'e':
				
				if(inHash && depth==1) {
					
					SHA1Bytes = md.digest();
					SHA1String = org.bintrotter.Utils.byteArrayToURLString( SHA1Bytes );					
					
					return;
				}
				
				if(inHash) {
					md.update((byte)b);
				}
				
				--depth;
				
				break;
			case 'i':
				
				if(inHash) {
					md.update((byte)b);
				}
				
				while((b = is.read()) != 'e') {
					
					if(inHash) {
						md.update((byte)b);
					}
				}
				
				if(inHash) {
					md.update((byte)b);
				}
				
				break;
			default:
				if(b < '0' || b > '9')
					throw new Exception("unexpected token" + b);
				
				sb = new StringBuilder();
				
				for(;;) {
					sb.append((char)b);
					
					if(inHash) {
						md.update((byte)b);
					}
					
					b = is.read();
					
					if(b<'0' || b>'9')
						break;
				}
				if(b != ':')
					throw new Exception("unexpected token" + b);
				
				if(inHash) {
					md.update((byte)b);
				}
				
				length = Integer.parseInt( sb.toString() );
				
				stringData = new byte[ length ];
				
				if(is.read(stringData) != length)
					throw new Exception("error reading string");
				
				if(inHash) {
					md.update(stringData);
				}
				
				if(depth==1 && !inHash) {
				
					if(Arrays.equals("info".getBytes(), stringData))
						inHash = true;
				}
				
				break;
			}
		}
	}
	
	
	
}


